home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / FragmentLinker / FragmentLinker.cpp next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  29.4 KB  |  641 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: FragmentLinker.cpp
  3. //
  4. // Starting point for new Direct3D applications
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //--------------------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9. #include "resource.h"
  10.  
  11. //#define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  12. //#define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  13.  
  14.  
  15. //--------------------------------------------------------------------------------------
  16. // Global variables
  17. //--------------------------------------------------------------------------------------
  18. ID3DXFont*              g_pFont = NULL;               // Font for drawing text
  19. ID3DXSprite*            g_pTextSprite = NULL;         // Sprite for batching draw text calls
  20. ID3DXEffect*            g_pEffect = NULL;             // D3DX effect interface
  21. CDXUTMesh               g_Mesh;                       // Mesh object
  22. CModelViewerCamera      g_Camera;                     // A model viewing camera
  23. bool                    g_bShowHelp = true;           // If true, it renders the UI control text
  24. CDXUTDialog             g_HUD;                        // dialog for standard controls
  25. CDXUTDialog             g_SampleUI;                   // dialog for sample specific controls
  26. D3DXVECTOR3             g_vObjectCenter;              // Center of bounding sphere of object
  27. FLOAT                   g_fObjectRadius;              // Radius of bounding sphere of object
  28. D3DXMATRIXA16           g_mCenterWorld;               // World matrix to center the mesh
  29.  
  30. DWORD                   g_dwShaderFlags;              // Shader compilation/linking flags
  31. ID3DXFragmentLinker*    g_pFragmentLinker = NULL;     // Fragment linker interface
  32. LPD3DXBUFFER            g_pCompiledFragments = NULL;  // Buffer containing compiled fragments
  33.                                                                  
  34.  
  35. //--------------------------------------------------------------------------------------
  36. // UI control IDs
  37. //--------------------------------------------------------------------------------------
  38. #define IDC_STATIC              -1
  39. #define IDC_TOGGLEFULLSCREEN    1
  40. #define IDC_TOGGLEREF           3
  41. #define IDC_CHANGEDEVICE        4
  42. #define IDC_ANIMATION           5
  43. #define IDC_LIGHTING            6
  44.  
  45.  
  46.  
  47. //--------------------------------------------------------------------------------------
  48. // Forward declarations 
  49. //--------------------------------------------------------------------------------------
  50. bool    CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed );
  51. void    CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps );
  52. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  53. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  54. void    CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  55. void    CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  56. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing );
  57. void    CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown  );
  58. void    CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl );
  59. void    CALLBACK OnLostDevice();
  60. void    CALLBACK OnDestroyDevice();
  61.  
  62. void    InitApp();
  63. HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh );
  64. void    RenderText();
  65.  
  66. HRESULT LinkVertexShader();
  67.  
  68.  
  69. //--------------------------------------------------------------------------------------
  70. // Entry point to the program. Initializes everything and goes into a message processing 
  71. // loop. Idle time is used to render the scene.
  72. //--------------------------------------------------------------------------------------
  73. INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
  74. {
  75.     // Set the callback functions. These functions allow the sample framework to notify
  76.     // the application about device changes, user input, and windows messages.  The 
  77.     // callbacks are optional so you need only set callbacks for events you're interested 
  78.     // in. However, if you don't handle the device reset/lost callbacks then the sample 
  79.     // framework won't be able to reset your device since the application must first 
  80.     // release all device resources before resetting.  Likewise, if you don't handle the 
  81.     // device created/destroyed callbacks then the sample framework won't be able to 
  82.     // recreate your device resources.
  83.     DXUTSetCallbackDeviceCreated( OnCreateDevice );
  84.     DXUTSetCallbackDeviceReset( OnResetDevice );
  85.     DXUTSetCallbackDeviceLost( OnLostDevice );
  86.     DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
  87.     DXUTSetCallbackMsgProc( MsgProc );
  88.     DXUTSetCallbackKeyboard( KeyboardProc );
  89.     DXUTSetCallbackFrameRender( OnFrameRender );
  90.     DXUTSetCallbackFrameMove( OnFrameMove );
  91.  
  92.     // Show the cursor and clip it when in full screen
  93.     DXUTSetCursorSettings( true, true );
  94.  
  95.     InitApp();
  96.  
  97.     // Initialize the sample framework and create the desired Win32 window and Direct3D 
  98.     // device for the application. Calling each of these functions is optional, but they
  99.     // allow you to set several options which control the behavior of the framework.
  100.     DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  101.     DXUTCreateWindow( L"FragmentLinker" );
  102.     DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );
  103.  
  104.     // Pass control to the sample framework for handling the message pump and 
  105.     // dispatching render calls. The sample framework will call your FrameMove 
  106.     // and FrameRender callback when there is idle time between handling window messages.
  107.     DXUTMainLoop();
  108.  
  109.     // Perform any application-level cleanup here. Direct3D device resources are released within the
  110.     // appropriate callback functions and therefore don't require any cleanup code here.
  111.  
  112.     return DXUTGetExitCode();
  113. }
  114.  
  115.  
  116. //--------------------------------------------------------------------------------------
  117. // Initialize the app 
  118. //--------------------------------------------------------------------------------------
  119. void InitApp()
  120. {
  121.     // Initialize dialogs
  122.     g_HUD.SetCallback( OnGUIEvent ); int iY = 10; 
  123.     g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
  124.     g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
  125.     g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22 );
  126.  
  127.     g_SampleUI.SetCallback( OnGUIEvent ); iY = 10; 
  128.     
  129.     // Title font for comboboxes
  130.     g_SampleUI.SetFont( 1, L"Arial", 14, FW_BOLD );
  131.     CDXUTElement* pElement = g_SampleUI.GetDefaultElement( DXUT_CONTROL_STATIC, 0 );
  132.     pElement->iFont = 1;
  133.     pElement->dwTextFormat = DT_LEFT | DT_BOTTOM;
  134.  
  135.     CDXUTComboBox* pComboBox = NULL;
  136.     g_SampleUI.AddStatic( IDC_STATIC, L"(V)ertex Animation", 20, 0, 105, 25 );
  137.     g_SampleUI.AddComboBox( IDC_ANIMATION, 20, 25, 140, 24, 'V', false, &pComboBox );
  138.     pComboBox->SetDropHeight( 30 );
  139.  
  140.     g_SampleUI.AddStatic( IDC_STATIC, L"(L)ighting", 20, 50, 105, 25 );
  141.     g_SampleUI.AddComboBox( IDC_LIGHTING, 20, 75, 140, 24, 'L', false, &pComboBox );
  142.     pComboBox->SetDropHeight( 30 );
  143.  
  144.     //g_SampleUI.AddCheckBox( IDC_ANIMATION, L"Vertex (A)nimation", 20, 60, 155, 20, true, 'A' );
  145. }
  146.  
  147.  
  148. //--------------------------------------------------------------------------------------
  149. // Called during device initialization, this code checks the device for some 
  150. // minimum set of capabilities, and rejects those that don't pass by returning false.
  151. //--------------------------------------------------------------------------------------
  152. bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, 
  153.                                   D3DFORMAT BackBufferFormat, bool bWindowed )
  154. {
  155.     // Skip backbuffer formats that don't support alpha blending
  156.     IDirect3D9* pD3D = DXUTGetD3DObject(); 
  157.     if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
  158.                     AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, 
  159.                     D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
  160.         return false;
  161.  
  162.     return true;
  163. }
  164.  
  165.  
  166. //--------------------------------------------------------------------------------------
  167. // This callback function is called immediately before a device is created to allow the 
  168. // application to modify the device settings. The supplied pDeviceSettings parameter 
  169. // contains the settings that the framework has selected for the new device, and the 
  170. // application can make any desired changes directly to this structure.  Note however that 
  171. // the sample framework will not correct invalid device settings so care must be taken 
  172. // to return valid device settings, otherwise IDirect3D9::CreateDevice() will fail.  
  173. //--------------------------------------------------------------------------------------
  174. void CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps )
  175. {
  176.     // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  177.     // then switch to SWVP.
  178.     if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
  179.          pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) )
  180.     {
  181.         pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  182.     }
  183.     else
  184.     {
  185.         pDeviceSettings->BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  186.     }
  187.  
  188.     // This application is designed to work on a pure device by not using 
  189.     // IDirect3D9::Get*() methods, so create a pure device if supported and using HWVP.
  190.     if ((pCaps->DevCaps & D3DDEVCAPS_PUREDEVICE) != 0 && 
  191.         (pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0 )
  192.         pDeviceSettings->BehaviorFlags |= D3DCREATE_PUREDEVICE;
  193.  
  194.     // Debugging vertex shaders requires either REF or software vertex processing 
  195.     // and debugging pixel shaders requires REF.  
  196. #ifdef DEBUG_VS
  197.     if( pDeviceSettings->DeviceType != D3DDEVTYPE_REF )
  198.     {
  199.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
  200.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;                            
  201.         pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  202.     }
  203. #endif
  204. #ifdef DEBUG_PS
  205.     pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
  206. #endif
  207. }
  208.  
  209.  
  210. //--------------------------------------------------------------------------------------
  211. // This callback function will be called immediately after the Direct3D device has been 
  212. // created, which will happen during application initialization and windowed/full screen 
  213. // toggles. This is the best location to create D3DPOOL_MANAGED resources since these 
  214. // resources need to be reloaded whenever the device is destroyed. Resources created  
  215. // here should be released in the OnDestroyDevice callback. 
  216. //--------------------------------------------------------------------------------------
  217. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  218. {
  219.     HRESULT hr;
  220.  
  221.     WCHAR strPath[MAX_PATH];
  222.  
  223.     // Initialize the font
  224.     V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, 
  225.                          OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, 
  226.                          L"Arial", &g_pFont ) );
  227.  
  228.     // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  229.     // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  230.     // processing, and debugging pixel shaders requires REF.  The 
  231.     // D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug experience in the 
  232.     // shader debugger.  It enables source level debugging, prevents instruction 
  233.     // reordering, prevents dead code elimination, and forces the compiler to compile 
  234.     // against the next higher available software target, which ensures that the 
  235.     // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  236.     // flags will cause slower rendering since the shaders will be unoptimized and 
  237.     // forced into software.  See the DirectX documentation for more information about 
  238.     // using the shader debugger.
  239.     g_dwShaderFlags = 0;
  240.     #ifdef DEBUG_VS
  241.         g_dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
  242.     #endif
  243.     #ifdef DEBUG_PS
  244.         g_dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
  245.     #endif
  246.  
  247.     // Read the D3DX effect file
  248.     
  249.     // If this fails, there should be debug output as to 
  250.     // they the .fx file failed to compile
  251.     
  252.     V_RETURN( DXUTFindDXSDKMediaFileCch( strPath, MAX_PATH, L"FragmentLinker.fx" ) );
  253.     V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, strPath, NULL, NULL, g_dwShaderFlags, 
  254.                                         NULL, &g_pEffect, NULL ) );
  255.  
  256.     // Load the mesh
  257.     V_RETURN( DXUTFindDXSDKMediaFileCch( strPath, MAX_PATH, L"dwarf\\dwarf.x" ) );
  258.     V_RETURN( g_Mesh.Create( pd3dDevice, strPath ) );
  259.  
  260.     // Find the mesh's center, then generate a centering matrix.
  261.     IDirect3DVertexBuffer9* pVB = NULL;
  262.     V_RETURN( g_Mesh.m_pSysMemMesh->GetVertexBuffer( &pVB ) );
  263.  
  264.     void* pVertices = NULL;
  265.     hr = pVB->Lock( 0, 0, &pVertices, 0 );
  266.     if( FAILED(hr) )
  267.     {
  268.         SAFE_RELEASE( pVB );
  269.         return hr;
  270.     }
  271.  
  272.     hr = D3DXComputeBoundingSphere( (D3DXVECTOR3*)pVertices, g_Mesh.m_pSysMemMesh->GetNumVertices(),
  273.                                     D3DXGetFVFVertexSize(g_Mesh.m_pSysMemMesh->GetFVF()), &g_vObjectCenter,
  274.                                     &g_fObjectRadius );
  275.     pVB->Unlock();
  276.     SAFE_RELEASE( pVB );
  277.  
  278.     if( FAILED(hr) )
  279.         return hr;
  280.  
  281.     D3DXMatrixTranslation( &g_mCenterWorld, -g_vObjectCenter.x, -g_vObjectCenter.y, -g_vObjectCenter.z );
  282.  
  283.     // Create the fragment linker interface
  284.     V_RETURN( D3DXCreateFragmentLinker( pd3dDevice, 0, &g_pFragmentLinker ) );
  285.  
  286.     // Compile the fragments to a buffer. The fragments must be linked together to form
  287.     // a shader before they can be used for rendering.
  288.     V_RETURN( DXUTFindDXSDKMediaFileCch( strPath, MAX_PATH, L"FragmentLinker.fx" ) );
  289.     V_RETURN( D3DXGatherFragmentsFromFile( strPath, NULL, NULL, g_dwShaderFlags, &g_pCompiledFragments, NULL ) );
  290.    
  291.     // Build the list of compiled fragments
  292.     V_RETURN( g_pFragmentLinker->AddFragments( (DWORD*)g_pCompiledFragments->GetBufferPointer() ) );
  293.  
  294.     // Store the fragment handles
  295.     CDXUTComboBox* pComboBox = NULL;
  296.     pComboBox = g_SampleUI.GetComboBox( IDC_LIGHTING );
  297.     pComboBox->RemoveAllItems();
  298.     pComboBox->AddItem( L"Ambient", (void*) g_pFragmentLinker->GetFragmentHandleByName( "AmbientFragment" ) );
  299.     pComboBox->AddItem( L"Ambient & Diffuse", (void*) g_pFragmentLinker->GetFragmentHandleByName( "AmbientDiffuseFragment" ) );
  300.     
  301.     pComboBox = g_SampleUI.GetComboBox( IDC_ANIMATION );
  302.     pComboBox->RemoveAllItems();
  303.     pComboBox->AddItem( L"On", (void*) g_pFragmentLinker->GetFragmentHandleByName( "ProjectionFragment_Animated" ) );
  304.     pComboBox->AddItem( L"Off", (void*) g_pFragmentLinker->GetFragmentHandleByName( "ProjectionFragment_Static" ) );
  305.     
  306.     // Link the desired fragments to create the vertex shader
  307.     V_RETURN( LinkVertexShader() );
  308.  
  309.     // Setup the camera's view parameters
  310.     D3DXVECTOR3 vecEye(3.0f, 0.0f, -3.0f);
  311.     D3DXVECTOR3 vecAt (0.0f, 0.0f, -0.0f);
  312.     g_Camera.SetViewParams( &vecEye, &vecAt );
  313.  
  314.     return S_OK;
  315. }
  316.  
  317.  
  318. //--------------------------------------------------------------------------------------
  319. // Link together compiled fragments to create a vertex shader. The list of fragments
  320. // used is determined by the currently selected UI options.
  321. //--------------------------------------------------------------------------------------
  322. HRESULT LinkVertexShader()
  323. {
  324.     HRESULT hr;
  325.     
  326.     const int NUM_FRAGMENTS = 2;
  327.     D3DXHANDLE aHandles[ NUM_FRAGMENTS ] = {0};
  328.     aHandles[ 0 ] = (D3DXHANDLE) g_SampleUI.GetComboBox( IDC_ANIMATION )->GetSelectedData();
  329.     aHandles[ 1 ] = (D3DXHANDLE) g_SampleUI.GetComboBox( IDC_LIGHTING )->GetSelectedData();
  330.  
  331.     // Link the fragments together to form a shader
  332.     IDirect3DVertexShader9* pVertexShader = NULL;
  333.     V_RETURN( g_pFragmentLinker->LinkVertexShader( "vs_1_1", g_dwShaderFlags, aHandles, NUM_FRAGMENTS, &pVertexShader, NULL ) );
  334.  
  335.     // Associate this vertex shader with the effect object
  336.     V_RETURN( g_pEffect->SetVertexShader( "MyVertexShader", pVertexShader ) );
  337.  
  338.     SAFE_RELEASE( pVertexShader );
  339.     return S_OK;
  340. }
  341.  
  342.  
  343. //--------------------------------------------------------------------------------------
  344. // This function loads the mesh and ensures the mesh has normals; it also optimizes the 
  345. // mesh for the graphics card's vertex cache, which improves performance by organizing 
  346. // the internal triangle list for less cache misses.
  347. //--------------------------------------------------------------------------------------
  348. HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh )
  349. {
  350.     ID3DXMesh* pMesh = NULL;
  351.     WCHAR str[MAX_PATH];
  352.     HRESULT hr;
  353.  
  354.     // Load the mesh with D3DX and get back a ID3DXMesh*.  For this
  355.     // sample we'll ignore the X file's embedded materials since we know 
  356.     // exactly the model we're loading.  See the mesh samples such as
  357.     // "OptimizedMesh" for a more generic mesh loading example.
  358.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, strFileName ) );
  359.  
  360.     V_RETURN( D3DXLoadMeshFromX(str, D3DXMESH_MANAGED, pd3dDevice, NULL, NULL, NULL, NULL, &pMesh) );
  361.  
  362.     DWORD *rgdwAdjacency = NULL;
  363.  
  364.     // Make sure there are normals which are required for lighting
  365.     if( !(pMesh->GetFVF() & D3DFVF_NORMAL) )
  366.     {
  367.         ID3DXMesh* pTempMesh;
  368.         V( pMesh->CloneMeshFVF( pMesh->GetOptions(), 
  369.                                   pMesh->GetFVF() | D3DFVF_NORMAL, 
  370.                                   pd3dDevice, &pTempMesh ) );
  371.         V( D3DXComputeNormals( pTempMesh, NULL ) );
  372.  
  373.         SAFE_RELEASE( pMesh );
  374.         pMesh = pTempMesh;
  375.     }
  376.  
  377.     // Optimize the mesh for this graphics card's vertex cache 
  378.     // so when rendering the mesh's triangle list the vertices will 
  379.     // cache hit more often so it won't have to re-execute the vertex shader 
  380.     // on those vertices so it will improve perf.     
  381.     rgdwAdjacency = new DWORD[pMesh->GetNumFaces() * 3];
  382.     if( rgdwAdjacency == NULL )
  383.         return E_OUTOFMEMORY;
  384.     V( pMesh->ConvertPointRepsToAdjacency(NULL, rgdwAdjacency) );
  385.     V( pMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL) );
  386.     delete []rgdwAdjacency;
  387.  
  388.     *ppMesh = pMesh;
  389.  
  390.     return S_OK;
  391. }
  392.  
  393.  
  394. //--------------------------------------------------------------------------------------
  395. // This callback function will be called immediately after the Direct3D device has been 
  396. // reset, which will happen after a lost device scenario. This is the best location to 
  397. // create D3DPOOL_DEFAULT resources since these resources need to be reloaded whenever 
  398. // the device is lost. Resources created here should be released in the OnLostDevice 
  399. // callback. 
  400. //--------------------------------------------------------------------------------------
  401. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, 
  402.                                 const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  403. {
  404.     HRESULT hr;
  405.  
  406.     if( g_pFont )
  407.         V_RETURN( g_pFont->OnResetDevice() );
  408.     if( g_pEffect )
  409.         V_RETURN( g_pEffect->OnResetDevice() );
  410.     g_Mesh.RestoreDeviceObjects( pd3dDevice );
  411.  
  412.     // Create a sprite to help batch calls when drawing many lines of text
  413.     V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pTextSprite ) );
  414.  
  415.     // Setup the camera's projection parameters
  416.     float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height;
  417.     g_Camera.SetProjParams( D3DX_PI/4, fAspectRatio, 0.1f, 1000.0f );
  418.     g_Camera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
  419.  
  420.     g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 );
  421.     g_HUD.SetSize( 170, 170 );
  422.     g_SampleUI.SetLocation( pBackBufferSurfaceDesc->Width-170, pBackBufferSurfaceDesc->Height-350 );
  423.     g_SampleUI.SetSize( 170, 300 );
  424.  
  425.     return S_OK;
  426. }
  427.  
  428.  
  429. //--------------------------------------------------------------------------------------
  430. // This callback function will be called once at the beginning of every frame. This is the
  431. // best location for your application to handle updates to the scene, but is not 
  432. // intended to contain actual rendering calls, which should instead be placed in the 
  433. // OnFrameRender callback.  
  434. //--------------------------------------------------------------------------------------
  435. void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  436. {
  437.     HRESULT hr;
  438.  
  439.     D3DXMATRIXA16 mWorld;
  440.     D3DXMATRIXA16 mView;
  441.     D3DXMATRIXA16 mProj;
  442.     D3DXMATRIXA16 mWorldViewProjection;
  443.    
  444.     // Update the camera's position based on user input 
  445.     g_Camera.FrameMove( fElapsedTime );
  446.  
  447.     // Get the projection & view matrix from the camera class
  448.     mWorld = g_mCenterWorld * *g_Camera.GetWorldMatrix();
  449.     mProj = *g_Camera.GetProjMatrix();
  450.     mView = *g_Camera.GetViewMatrix();
  451.  
  452.     mWorldViewProjection = mWorld * mView * mProj;
  453.  
  454.     // Update the effect's variables.  Instead of using strings, it would 
  455.     // be more efficient to cache a handle to the parameter by calling 
  456.     // ID3DXEffect::GetParameterByName
  457.     V( g_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProjection ) );
  458.     V( g_pEffect->SetMatrix( "g_mWorld", &mWorld ) );
  459.     V( g_pEffect->SetFloat( "g_fTime", (float)fTime ) );        
  460. }
  461.  
  462.  
  463. //--------------------------------------------------------------------------------------
  464. // This callback function will be called at the end of every frame to perform all the 
  465. // rendering calls for the scene, and it will also be called if the window needs to be 
  466. // repainted. After this function has returned, the sample framework will call 
  467. // IDirect3DDevice9::Present to display the contents of the next buffer in the swap chain
  468. //--------------------------------------------------------------------------------------
  469. void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  470. {
  471.     HRESULT hr;
  472.      
  473.     // Clear the render target and the zbuffer 
  474.     V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 45, 50, 170), 1.0f, 0) );
  475.  
  476.     // Render the scene
  477.     if( SUCCEEDED( pd3dDevice->BeginScene() ) )
  478.     {  
  479.         // Apply the technique contained in the effect
  480.         UINT cPasses, iPass;
  481.         V( g_pEffect->Begin(&cPasses, 0) );
  482.  
  483.         for (iPass = 0; iPass < cPasses; iPass++)
  484.         {
  485.             V( g_pEffect->BeginPass(iPass) );
  486.  
  487.             // Render the mesh with the applied technique
  488.             V( g_Mesh.Render( pd3dDevice ) );
  489.  
  490.             V( g_pEffect->EndPass() );
  491.         }
  492.         V( g_pEffect->End() );
  493.  
  494.         RenderText();
  495.         V( g_HUD.OnRender( fElapsedTime ) );
  496.         V( g_SampleUI.OnRender( fElapsedTime ) );
  497.  
  498.         V( pd3dDevice->EndScene() );
  499.     }
  500. }
  501.  
  502.  
  503. //--------------------------------------------------------------------------------------
  504. // Render the help and statistics text. This function uses the ID3DXFont interface for 
  505. // efficient text rendering.
  506. //--------------------------------------------------------------------------------------
  507. void RenderText()
  508. {
  509.     // The helper object simply helps keep track of text position, and color
  510.     // and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
  511.     // If NULL is passed in as the sprite object, then it will work however the 
  512.     // pFont->DrawText() will not be batched together.  Batching calls will improves performance.
  513.     CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );
  514.  
  515.     // Output statistics
  516.     txtHelper.Begin();
  517.     txtHelper.SetInsertionPos( 5, 5 );
  518.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
  519.     txtHelper.DrawTextLine( DXUTGetFrameStats() );
  520.     txtHelper.DrawTextLine( DXUTGetDeviceStats() );
  521.     txtHelper.DrawTextLine( L"Selected fragments are linked on-the-fly to create the current shader" );
  522.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  523.     
  524.     // Draw help
  525.     if( g_bShowHelp )
  526.     {
  527.         const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
  528.         txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-15*6 );
  529.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.75f, 0.0f, 1.0f ) );
  530.         txtHelper.DrawTextLine( L"Controls:" );
  531.  
  532.         txtHelper.SetInsertionPos( 20, pd3dsdBackBuffer->Height-15*5 );
  533.         txtHelper.DrawTextLine( L"Rotate model: Left mouse button\n"
  534.                                 L"Rotate camera: Right mouse button\n"
  535.                                 L"Zoom camera: Mouse wheel scroll\n" );
  536.  
  537.         txtHelper.SetInsertionPos( 250, pd3dsdBackBuffer->Height-15*5 );
  538.         txtHelper.DrawTextLine( L"Hide help: F1\n" 
  539.                                 L"Quit: ESC\n" );
  540.     }
  541.     else
  542.     {
  543.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  544.         txtHelper.DrawTextLine( L"Press F1 for help" );
  545.     }
  546.     txtHelper.End();
  547. }
  548.  
  549.  
  550. //--------------------------------------------------------------------------------------
  551. // Before handling window messages, the sample framework passes incoming windows 
  552. // messages to the application through this callback function. If the application sets 
  553. // *pbNoFurtherProcessing to TRUE, then the sample framework will not process this message.
  554. //--------------------------------------------------------------------------------------
  555. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing )
  556. {
  557.     // Give the dialogs a chance to handle the message first
  558.     *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
  559.     if( *pbNoFurtherProcessing )
  560.         return 0;
  561.     *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
  562.     if( *pbNoFurtherProcessing )
  563.         return 0;
  564.  
  565.     // Pass all remaining windows messages to camera so it can respond to user input
  566.     g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
  567.  
  568.     return 0;
  569. }
  570.  
  571.  
  572. //--------------------------------------------------------------------------------------
  573. // As a convenience, the sample framework inspects the incoming windows messages for
  574. // keystroke messages and decodes the message parameters to pass relevant keyboard
  575. // messages to the application.  The framework does not remove the underlying keystroke 
  576. // messages, which are still passed to the application's MsgProc callback.
  577. //--------------------------------------------------------------------------------------
  578. void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown )
  579. {
  580.     if( bKeyDown )
  581.     {
  582.         switch( nChar )
  583.         {
  584.             case VK_F1: g_bShowHelp = !g_bShowHelp; break;
  585.         }
  586.     }
  587. }
  588.  
  589.  
  590. //--------------------------------------------------------------------------------------
  591. // Handles the GUI events
  592. //--------------------------------------------------------------------------------------
  593. void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl )
  594. {
  595.     switch( nControlID )
  596.     {
  597.         case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break;
  598.         case IDC_TOGGLEREF:        DXUTToggleREF(); break;
  599.         case IDC_CHANGEDEVICE:     DXUTSetShowSettingsDialog( !DXUTGetShowSettingsDialog() ); break;
  600.         case IDC_ANIMATION:        LinkVertexShader(); break;
  601.         case IDC_LIGHTING:         LinkVertexShader(); break;
  602.     }
  603. }
  604.  
  605.  
  606. //--------------------------------------------------------------------------------------
  607. // This callback function will be called immediately after the Direct3D device has 
  608. // entered a lost state and before IDirect3DDevice9::Reset is called. Resources created
  609. // in the OnResetDevice callback should be released here, which generally includes all 
  610. // D3DPOOL_DEFAULT resources. See the "Lost Devices" section of the documentation for 
  611. // information about lost devices.
  612. //--------------------------------------------------------------------------------------
  613. void CALLBACK OnLostDevice()
  614. {
  615.     if( g_pFont )
  616.         g_pFont->OnLostDevice();
  617.     if( g_pEffect )
  618.         g_pEffect->OnLostDevice();
  619.     g_Mesh.InvalidateDeviceObjects();
  620.     SAFE_RELEASE(g_pTextSprite);
  621. }
  622.  
  623.  
  624. //--------------------------------------------------------------------------------------
  625. // This callback function will be called immediately after the Direct3D device has 
  626. // been destroyed, which generally happens as a result of application termination or 
  627. // windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  628. // should be released here, which generally includes all D3DPOOL_MANAGED resources. 
  629. //--------------------------------------------------------------------------------------
  630. void CALLBACK OnDestroyDevice()
  631. {
  632.     SAFE_RELEASE( g_pEffect );
  633.     SAFE_RELEASE( g_pFont );
  634.     g_Mesh.Destroy();
  635.     SAFE_RELEASE( g_pFragmentLinker );
  636.     SAFE_RELEASE( g_pCompiledFragments );
  637. }
  638.  
  639.  
  640.  
  641.